TargetArticle targetArticle;
SourceArticle sourceArticle;

int myWidth = 600;//(int)(screen.availWidth * 0.5);
int myHeight = 500;//(int)(screen.availHeight * 0.75);

int tArticlePosX = (int)(0.1 * myWidth);
int tArticlePosY = (int)(0.05 * myHeight);
int tArticlePosW = (int)(0.3 * myWidth);
int tArticlePosH = (int)(0.9 * myHeight);

int sArticlePosX = (int)(0.6 * myWidth);
int sArticlePosY = (int)(0.05 * myHeight);
int sArticlePosW = (int)(0.3 * myWidth);
int sArticlePosH = (int)(0.9 * myHeight);
/*
*/
int percentPadding = 3;

// Variable to show when it's in the lower limit of the level
int tCurrentLevel;
int sCurrentLevel;

// Variable to indicate a transclusion has been made
boolean transclusionStarted = false;

// Temp variable to the clicked section
Section tempTranscludedSection = null;

// Boolean variable to insert before/after a section
boolean insertBefore = false;

void setup() {
  size(myWidth, myHeight);

  sourceArticle = new SourceArticle(sArticlePosX, sArticlePosY, sArticlePosW, sArticlePosH, percentPadding);
  targetArticle = new TargetArticle(tArticlePosX, tArticlePosY, tArticlePosW, tArticlePosH, percentPadding);

  sourceArticle.setSectionsColor ( color ( 50, 150, 50 ) );
  targetArticle.setSectionsColor ( color ( 50, 50, 150 ) );

  tCurrentLevel = 0;
  sCurrentLevel = 0;

  cursor(CROSS);
}

void draw() {
  background(180);

  targetArticle.draw();
  sourceArticle.draw();

  if ( transclusionStarted ) { // If the transclusion had started then draw the hand and the rectangle
    // Exits the status "PREVIEW"
    previewText("");

    fill (255);

    tempTSW = (int)( tempTranscludedSection.getWidth() / 4 );
    tempTSH = (int)( tempTranscludedSection.getHeight() / 4 );

    rect(mouseX - tempTSW, mouseY - tempTSH, ( tempTSW * 2 ), ( tempTSH * 2 ) );
  }
}

void keyPressed() {
  boolean didZoom = false;

  if ( key == 't' ) {
    tZoomIn();
    didZoom = true;
  }

  if ( key == 'T' ) {
    tZoomOut();
    didZoom = true;
  }

  if ( key == 's' ) {
    sZoomIn();
    didZoom = true;
  }

  if ( key == 'S' ) {
    sZoomOut();
    didZoom = true;
  }
/*
  // To insert before or after a section
  if ( key == 'b' || key == 'B' ) {
    insertBefore = true;
  }

  if ( key == 'a' || key == 'A' ) {
    insertBefore = false;
  }
*/
  if (didZoom) {
    sourceArticle.resetSectionsStatus();
    targetArticle.resetSectionsStatus();
    previewText("");
  }
}

void mouseDragged() {
  if ( mouseButton == LEFT ) {
    if ( !transclusionStarted ) {
      if ( sourceArticle.sectionClicked() ) {
        transclusionStarted = true;

        // We get the clicked section
        tempTranscludedSection = sourceArticle.getClickedSection();
        tempTranscludedSection.setStatus("IN_TRANSCLUSION");
      }
    }
  }
}

void mouseReleased() {
  if ( transclusionStarted ) {
    // The section is transcluded
    if ( targetArticle.sectionClicked() ) {
      targetArticle.addNewTranscludedSection ( tempTranscludedSection, targetArticle.getClickedSection() );
    }

    transclusionStarted = false;

    tempTranscludedSection.setStatus("IDLE");
    showTooltip("");
  }
}

void mouseClicked() {
  if ( mouseButton == LEFT) {
    sourceArticle.resetSectionsStatus();  // For sections with "IDLE" status
    targetArticle.resetSectionsStatus();

    if ( sourceArticle.sectionClicked() ) {
      sourceArticle.changeClickedSectionStatus("PREVIEW");
    }
    else {
      if ( targetArticle.sectionClicked() ) {
        targetArticle.changeClickedSectionStatus("PREVIEW");
      }
      else {
        // Exits the status
        previewText("");
      }
    }
  }

  if ( mouseButton == RIGHT ) {
    sourceArticle.resetSectionsStatus();  // For sections with "IDLE" status
    targetArticle.resetSectionsStatus();

    if ( targetArticle.sectionClicked() ) {
      targetArticle.changeClickedSectionStatus("DELETE");
    }
  }
}

void tZoomIn() {
  if ( tCurrentLevel < ( targetLevels.length() - 1 ) ) {
    tCurrentLevel++;

    loadTargetArticleSketch( tCurrentLevel );
  }
}

void tZoomOut() {
  if (tCurrentLevel > 0) {
    tCurrentLevel--;

    loadTargetArticleSketch( tCurrentLevel );
  }
}

void sZoomIn() {
  if ( sCurrentLevel < ( sourceLevels.length() - 1 ) ) {
    sCurrentLevel++;

    loadSourceArticleSketch( sCurrentLevel );
  }
}

void sZoomOut() {
  if (sCurrentLevel > 0) {
    sCurrentLevel--;

    loadSourceArticleSketch( sCurrentLevel );
  }
}

void loadTargetArticleSketch(int newLevel) {
  targetArticle.resetAndDeleteSections();

  // Level 0 of text (lowest one)
  for (int i=0; i<targetSectionsContent.length(); i++) {
    if ( targetSectionsLevel[i] == targetLevels[newLevel] ) {
      targetArticle.addNewSection( targetSectionsContent[i], (int)targetSectionsIndex[i] );
    }
  }

  // Color
  targetArticle.setSectionsColor( color( 50, 50, 100 + (int)(( 150 / targetLevels.length() ) * newLevel) ) );
}

void loadSourceArticleSketch(int newLevel) {
  sourceArticle.resetAndDeleteSections();

  // Level 0 of text (lowest one)
  for (int i=0; i<sourceSectionsContent.length(); i++) {
    if ( sourceSectionsLevel[i] == sourceLevels[newLevel] ) {
      sourceArticle.addNewSection( sourceSectionsContent[i] , (int)sourceSectionsIndex[i] );
    }
  }

  // Color
  sourceArticle.setSectionsColor( color( 50, 100 + (int)(( 150 / sourceLevels.length() ) * newLevel), 50 ) );
}

/************************************************************************** ARTICLE **************************************************************************/
public class Article {
  private ArrayList <Section> articleSections;

  private float articleX;
  private float articleY;
  private float articleW;
  private float articleH;

  private float articlePadding;

  public Article(float newX, float newY, float newW, float newH, int newP) {
    articleSections = new ArrayList<Section>();

    this.articleX = newX;
    this.articleY = newY;
    this.articleW = newW;
    this.articleH = newH;

    this.articlePadding = (float)( (newP * newW)/ 100 );
  }

  public void addNewSection(String newContent, int newIndex) {
    Section newSection = new Section(newContent, newIndex);

    // TODO: Revisar esto --------------------------------------------------------------------------------------------------
    newSection.setStatus("IDLE");

    articleSections.add(newSection);
  }

  public void addNewSectionWithIndex(int indexOfNewSection, Section newSection) {
    articleSections.add(indexOfNewSection, newSection);
  }

  public void draw() {
    fill(255);

    rect(articleX, articleY, articleW, articleH);

    drawSections();
  }

  private void drawSections() {
    Section tempSection;
    float drawingArea = articleH - ((articleSections.size() + 1) * articlePadding);
    float totalSectionsHeight = 0;
    float newPosY = articleY;


    for (int i=0; i<articleSections.size(); i++) {
      tempSection = this.getSection(i);

      totalSectionsHeight = totalSectionsHeight + tempSection.getSectionSize();
    }

    for (int i=0; i<articleSections.size(); i++) {
      tempSection = this.getSection(i);

      tempSection.draw(articleX, newPosY, articleW, (float)(tempSection.getSectionSize() / totalSectionsHeight) * drawingArea, articlePadding);

      newPosY  = newPosY + (float)( (tempSection.getSectionSize() * drawingArea) / totalSectionsHeight) + articlePadding;
    }
  }

  protected Section getSection(int index) {
    Section tempSection;

    tempSection = (Section)articleSections.get(index);

    return tempSection;
  }

  public void setSectionsColor(color newColor) {
    Section tempSection;

    for (int i=0; i<articleSections.size(); i++) {
      tempSection = this.getSection(i);

      tempSection.setColor(newColor);
    }
  }

  public void resetAndDeleteSections() {
    articleSections = new ArrayList<Section>();
  }

  public boolean sectionClicked() {
    Section tempSection;
    boolean hasSectionClicked = false;

    for (int i=0; i<articleSections.size(); i++) {
      tempSection = this.getSection(i);

      if ( tempSection.mouseOver() ) {
        hasSectionClicked = true;
      }
    }

    return hasSectionClicked;
  }

  public Section getClickedSection() {
    Section tempSection, returnSection;
    returnSection = null;

    for (int i=0; i<articleSections.size(); i++) {
      tempSection = this.getSection(i);

      if ( tempSection.mouseOver() ) {
        returnSection = tempSection;
      }
    }

    return returnSection;
  }

  public void resetSectionsStatus() {
    Section tempSection;

    for (int i=0; i<articleSections.size(); i++) {
      tempSection = this.getSection(i);

      if ( tempSection.getStatus() == "PREVIEW" ) {
        tempSection.setStatus("IDLE");
      }
    }
  }

  public void changeClickedSectionStatus(String newStatus) {
    Section tempSection = getClickedSection();

    if ( tempSection.getStatus() != "TRANSCLUDED" ) {
      if ( newStatus != "DELETE" ) {
        tempSection.setStatus( newStatus );
      }
    }
    else {
      // If it is a transcluded section and it is wanted to be deleted
      if ( newStatus == "DELETE" ) {
        tempSection.releaseParent();
        articleSections.remove( tempSection );
      }
    }
  }
}

/************************************************************************** SOURCE ARTICLE **************************************************************************/
public class SourceArticle extends Article {
  public SourceArticle(float newX, float newY, float newW, float newH, int newP) {
    super(newX, newY, newW, newH, newP);
  }

  public void draw() {
    super.draw();

    // Add new functionalities
  }
}

/************************************************************************** TARGET ARTICLE **************************************************************************/
public class TargetArticle extends Article {
  public TargetArticle(float newX, float newY, float newW, float newH, int newP) {
    super(newX, newY, newW, newH, newP);
  }

  public void draw() {
    super.draw();

    // Add new functionalities
  }

  public void addNewTranscludedSection( Section tSection, Section whichSection ) { // tSec
    int indexOfSection = this.articleSections.indexOf(whichSection);

    if ( insertBefore == false ) {
      indexOfSection++;
    }

    // The new section is cloned
    Section newSection = new Section( tSection.getSectionContent(), tSection.getColor(), "TRANSCLUDED", tSection, whichSection.getSectionIndex() ) ;

    super.addNewSectionWithIndex(indexOfSection, newSection);

    //register this in the js file
    registerNewTranscludedSection( whichSection.getSectionIndex() , tSection.getSectionIndex() , sourceLevels[sCurrentLevel] ); // *******************************************************************************
  }
}

/************************************************************************** SECTION **************************************************************************/
public class Section {
  private String sectionContent;
  private color sectionColor;

  private float sectionX;
  private float sectionY;
  private float sectionW;
  private float sectionH;

  private String sectionStatus;

  private Section parentSection = null; // Parent of this TRANSCLUDED section

  private boolean forceHighlightFlag = false;

  private int sectionIndex;

  public Section(String newSectionContent, int newIndex) {
    this.sectionContent = newSectionContent;
    this.sectionIndex = newIndex;
  }

  public Section(String newSectionContent, color newSectionColor, String newSectionStatus, Section newParentSection, int indexOfTarget) {
    this.sectionContent = newSectionContent;
    this.sectionColor = newSectionColor;
    this.sectionStatus = newSectionStatus;
    this.parentSection = newParentSection;

    sectionIndex = indexOfTarget;
  }

  public int getSectionIndex(){
    return sectionIndex;
  }

  public void releaseParent() {
    parentSection.forceHighlight( false );
  }

  public void forceHighlight(boolean newForceHighlight) {
    this.forceHighlightFlag = newForceHighlight;
  }

  public void setStatus(String newStatus) {
    this.sectionStatus = newStatus;
  }

  public String getStatus() {
    return this.sectionStatus;
  }

  public float getWidth() {
    return this.sectionW;
  }

  public float getHeight() {
    return this.sectionH;
  }

  public void draw(float posX, float posY, float objW, float objH, float padding) {
    if (sectionStatus == "IDLE") {
      if ( mouseOver() || forceHighlightFlag) {
        fill(200);
      }
      else {
        fill(sectionColor);
      }
    }

    if (sectionStatus == "PREVIEW") {
      fill(212);
      previewText(this.sectionContent);
    }

    if ( sectionStatus == "IN_TRANSCLUSION" ) {
      fill( color (255, 0, 0) );
/*
      String whereText;

      if (insertBefore) {
        whereText = "BEFORE";
      }
      else {
        whereText = "AFTER";
      }

      showTooltip("insert " + whereText + " this (toogle with 'a' or 'b')" );
*/      
    }

    if ( sectionStatus == "TRANSCLUDED" ) {
      if ( mouseOver() ) {
        fill(200);

        this.parentSection.forceHighlight(true);
      }
      else {
        fill(sectionColor);
        this.parentSection.forceHighlight(false);

/*
        if ( this.parentSection.getHighlightStatus() ) {

        }
        else{
          this.parentSection.forceHighlight(false);
        }
*/
      }
    }

    // This is done to be able to hightlight the section when the mouse is over
    sectionX = posX + padding;
    sectionY = posY + padding;
    sectionW = objW - 2*padding;
    sectionH = objH;

    rect(sectionX, sectionY, sectionW, sectionH);
  }

  public int getSectionSize() {
    return (int)( log( this.sectionContent.length() ) / log(2) );
  }

  public boolean mouseOver() {
    boolean isOver = true;

    if (mouseX < sectionX) {
      isOver = false;
    }

    if (mouseX > (sectionX + sectionW)) {
      isOver = false;
    }

    if (mouseY < sectionY) {
      isOver = false;
    }

    if (mouseY > (sectionY + sectionH)) {
      isOver = false;
    }

    return isOver;
  }

  public void setColor(color newColor) {
    this.sectionColor = newColor;
  }

  public color getColor() {
    return this.sectionColor;
  }

  public String getSectionContent() {
    return this.sectionContent;
  }

  public boolean getHighlightStatus() {
    return forceHighlightFlag;
  }
}

